/* Certificate creation for TPM EK.
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/pem.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/x509v3.h>
#include <trousers/tss.h>
#include <trousers/trousers.h>
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <time.h>
#endif

#define TPM_GEO "XEN_GEO_BANGLORE"

void log_msg(char* file,int line,char *msg, ...);

#define SHA_DIGEST_LENGTH 20

#define TPM_NV_INDEX_GEO    ((UINT32)0x00000005)


/* Generate a pu key in PEM format
 *openssl rsa -in ssh_host_rsa_key -pubout > /etc/tpm/xen.pub
 */


#define BSIZE	128
#define CKERR	if (result != TSS_SUCCESS) goto error

/* Definitions from section 7 of
 * TCG PC Client Specific Implementation Specification
 * For Conventional BIOS
 */
#define TCG_TAG_PCCLIENT_STORED_CERT		0x1001
#define TCG_TAG_PCCLIENT_FULL_CERT		0x1002
#define TCG_TAG_PCCLIENT_PART_SMALL_CERT	0x1003
#define TCG_FULL_CERT				0
#define TCG_PARTIAL_SMALL_CERT			1


/*
 *Function tries to read a TPM
 *certificate from NV_RAM 
 * return 0 on success
 * 
 * */

FILE *log_filp;

/* Read the TPM EK
 * TODO : generate one and insert if does not exist
 * 
 */

unsigned char tpm_key[SHA_DIGEST_LENGTH] ;
unsigned char key_hash[] = "3beac9388f9b489d50bb01e2ff0fa2aaa9ee1d73" ;

static char get_val(char c)
{
    if (isdigit(c))
        return  ( c - '0');
    else if (isupper(c))
        return  (c - 'A' + 10);
    else if (islower(c))
        return (c - 'a' + 10);
    return -1;
}


static int get_key_bytes(unsigned char * md, unsigned char * buf)
{
    int i;
    char t1;
    char t2;
    for (i = 0;i < SHA_DIGEST_LENGTH; i++) {
        t1 = get_val(buf[i*2]);
        t2 = get_val(buf[i*2+1]);
        if( t1 < 0 || t2 < 0) {
            return 1;
        }
        md[i] = (t1 << 4) + t2;
    }
    return 0;
}


int set_credential(BYTE * cert , UINT32 len)
{

//CONTEXT SECTION
	TSS_RESULT		result;
	TSS_HCONTEXT	context;
	TSS_HPOLICY		policy_default;
	
    result = Tspi_Context_Create(&context);CKERR;
	result = Tspi_Context_Connect(context, NULL);CKERR;
	result = Tspi_Context_GetDefaultPolicy(context, &policy_default);CKERR;


//TPM SECTION
	TSS_HTPM		tpm;
	TSS_HPOLICY		policy_tpm;


	result = Tspi_Context_GetTpmObject(context, &tpm);

	result = Tspi_Context_CreateObject(context, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &policy_tpm);CKERR;

	//result = Tspi_Policy_SetSecret(policy_tpm, TSS_SECRET_MODE_PLAIN, (UINT32)strlen(TPMPASSWD),(BYTE*)TPMPASSWD);CKERR;

    result = Tspi_Policy_SetSecret((policy_tpm), TSS_SECRET_MODE_SHA1,
            (UINT32)(sizeof(tpm_key)), (BYTE*)tpm_key);
    if (result != TSS_SUCCESS) {
        printf( "Tspi_SetSecret failed with 0x%X %s",
                result, Trspi_Error_String(result));
	    CKERR;
        }
    result = Tspi_Policy_AssignToObject(policy_tpm, tpm);CKERR;


//NVSTORE SECTION
	TSS_HNVSTORE	nvstore;

	result = Tspi_Context_CreateObject(context, TSS_OBJECT_TYPE_NV, NULL, &nvstore);CKERR;

	result = Tspi_Policy_AssignToObject(policy_tpm, nvstore);CKERR;

	//result = Tspi_SetAttribUint32(nvstore, TSS_TSPATTRIB_NV_INDEX, NULL, TPM_NV_INDEX_EKCert);CKERR;
	result = Tspi_SetAttribUint32(nvstore, TSS_TSPATTRIB_NV_INDEX, NULL, TPM_NV_INDEX_GEO);CKERR;

	result = Tspi_SetAttribUint32(nvstore, TSS_TSPATTRIB_NV_PERMISSIONS, NULL, TPM_NV_PER_OWNERWRITE);CKERR;

	result = Tspi_SetAttribUint32(nvstore, TSS_TSPATTRIB_NV_DATASIZE, NULL, len);CKERR;

    result = Tspi_NV_DefineSpace(nvstore, NULL, NULL);CKERR;

	result = Tspi_NV_WriteValue(nvstore, 0, len, cert);CKERR;


//CLEANUP SECTION
	result = Tspi_Context_CloseObject(context, policy_tpm); CKERR;
	result = Tspi_Context_FreeMemory(context, NULL);
	result = Tspi_Context_Close(context);CKERR;
    fprintf(stdout,"%s\n","Success in insert");
    return;
    
    error:
        fprintf(stdout, "%s %s \n","Error in set_credential ",Trspi_Error_String(result));
	    return;
   
}



void get_credential()
{

//CONTEXT SECTION
    TSS_RESULT		result;
	TSS_HCONTEXT	context;
	TSS_HPOLICY		policy_default;
    UINT32			cred_size = strlen(TPM_GEO);
    BYTE*			cred_blob;
    UINT32 i;
    cred_blob = calloc(sizeof(BYTE),strlen(TPM_GEO));
	
    result = Tspi_Context_Create(&context);CKERR;
	result = Tspi_Context_Connect(context, NULL);CKERR;
	result = Tspi_Context_GetDefaultPolicy(context, &policy_default);CKERR;

//TPM SECTION
	TSS_HTPM		tpm;
	TSS_HPOLICY		policy_tpm;


	result = Tspi_Context_GetTpmObject(context, &tpm);

	result = Tspi_Context_CreateObject(context, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &policy_tpm);CKERR;

	//result = Tspi_Policy_SetSecret(policy_tpm, TSS_SECRET_MODE_PLAIN, (UINT32)strlen(TPMPASSWD),(BYTE*)TPMPASSWD);CKERR;

    result = Tspi_Policy_SetSecret((policy_tpm), TSS_SECRET_MODE_SHA1,
            (UINT32)(sizeof(tpm_key)), (BYTE*)tpm_key);
    if (result != TSS_SUCCESS) {
        printf( "Tspi_SetSecret failed with 0x%X %s",
                result, Trspi_Error_String(result));
        CKERR;
    }  
	result = Tspi_Policy_AssignToObject(policy_tpm, tpm);CKERR;

//NVSTORE SECTION


	TSS_HNVSTORE	nvstore;

	result = Tspi_Context_CreateObject(context, TSS_OBJECT_TYPE_NV, NULL, &nvstore);CKERR;

	result = Tspi_Policy_AssignToObject(policy_tpm, nvstore);CKERR;

	result = Tspi_SetAttribUint32(nvstore, TSS_TSPATTRIB_NV_INDEX, NULL, TPM_NV_INDEX_GEO);CKERR;

	result = Tspi_NV_ReadValue(nvstore, 0, &cred_size, &cred_blob);CKERR;
	
    if (result == 0) {
    	fprintf(stdout,"%s\n","Got the data ");
        for (i = 0; i < cred_size; i++)
            fprintf(stdout,"\t %c",(char)cred_blob[i]);
	
	result = Tspi_Context_FreeMemory(context, cred_blob);
	}
    	fprintf(stdout,"\n %s\n","done ");
	result = Tspi_Context_CloseObject(context, policy_tpm);CKERR;
	//result = Tspi_Context_CloseObject(context, nvstore);CKERR;
	result = Tspi_Context_Close(context);
   
    fprintf(stdout,"%s\n","Success in get credential");
	return;
    error:
        fprintf(stdout, "%s %s","Error in get_credential ",Trspi_Error_String(result));
	    return;
   
}

void clear_credential()
{
//CONTEXT SECTION
	TSS_RESULT		result;
	TSS_HCONTEXT	context;
	TSS_HPOLICY		policy_default;
	
    result = Tspi_Context_Create(&context);CKERR;
	result = Tspi_Context_Connect(context, NULL);CKERR;
	result = Tspi_Context_GetDefaultPolicy(context, &policy_default);CKERR;
//TPM SECTION
	TSS_HTPM		tpm;
	TSS_HPOLICY		policy_tpm;

	result = Tspi_Context_GetTpmObject(context, &tpm);

	result = Tspi_Context_CreateObject(context, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &policy_tpm);CKERR;

	//result = Tspi_Policy_SetSecret(policy_tpm, TSS_SECRET_MODE_PLAIN, (UINT32)strlen(TPMPASSWD),(BYTE*)TPMPASSWD);CKERR;
    result = Tspi_Policy_SetSecret((policy_tpm), TSS_SECRET_MODE_SHA1,
            (UINT32)(sizeof(tpm_key)), (BYTE*)tpm_key);
    if (result != TSS_SUCCESS) {
        printf( "Tspi_SetSecret failed with 0x%X %s",
                result, Trspi_Error_String(result));
        CKERR;
    }
	result = Tspi_Policy_AssignToObject(policy_tpm, tpm);CKERR;

//NVSTORE SECTION
	TSS_HNVSTORE	nvstore;

	result = Tspi_Context_CreateObject(context, TSS_OBJECT_TYPE_NV, NULL, &nvstore);CKERR;

	result = Tspi_Policy_AssignToObject(policy_tpm, nvstore);CKERR;

	result = Tspi_SetAttribUint32(nvstore, TSS_TSPATTRIB_NV_INDEX, NULL, TPM_NV_INDEX_GEO);CKERR;

	result = Tspi_NV_ReleaseSpace(nvstore);CKERR;

//CLEANUP SECTION
	result = Tspi_Context_CloseObject(context, policy_tpm);CKERR;
	//result = Tspi_Context_CloseObject(context, nvstore);CKERR;
	result = Tspi_Context_Close(context);CKERR;
    fprintf(stdout,"%s","Success in cleart");
    return;
    error:
        fprintf(stdout, "%s %s \n ","Error in clear_credential",Trspi_Error_String(result));
	    return;
   
}

int main(int argc, char **av)
{
    BYTE * cert;
    UINT32 certLen;
    FILE * fp ; 
    log_filp = stdout;//fopen(LOG_FILE,"a+");
    
    if (!log_filp) {
        exit(1);
    }
/*	if ((fp = fopen (av[1], "rb")) == NULL) {
		fprintf (stderr, "Unable to open file %s\n", av[1]);
		exit (1);
	} 
	fseek (fp, 0, SEEK_END);
	certLen= ftell (fp);
	fseek (fp, 0, SEEK_SET);
	cert = (BYTE*)malloc (certLen);
	
    if (fread (cert, 1, certLen, fp) != certLen) {
		fprintf (stdout, "Unable to read file %s\n", av[1]);
		exit (1);
	}
	fclose (fp);
*/    
    get_key_bytes(tpm_key, key_hash);
    clear_credential();
    set_credential(TPM_GEO,strlen(TPM_GEO));
    //set_credential("HELLO WORLD",11);
    get_credential();
    return(0);
}

